package com.galen.manual.utils;

import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

/**
 * 用户上下文工具类
 * 用于从HTTP请求中提取用户相关信息，与现有JWT用户上下文系统集成
 */
@Slf4j
public class UserContextUtil {
    private static final List<String> WHITE_LIST = List.of(
            // Swagger相关路径
            "/api-docs/**",
            "/swagger-ui/**",
            "/swagger-ui.html",
            "/swagger-ui/index.html",
            "/swagger-resources/**",
            "/webjars/**",
            "/v2/api-docs",
            "/v2/api-docs/**",
            "/v3/api-docs",
            "/v3/api-docs/**",
            // 认证相关路径
            "/api/auth/login",
            "/api/auth/register",
            "/api/auth/logout",
            "/api/auth/refresh",
            "/api/auth/verify",
            "/api/auth/forget",
            "/api/auth/reset",
            "/api/auth/send-code",
            "/api/auth/verify-code",
            "/api/auth/send-reset-code",
            "/api/auth/verify-reset-code",
            "/api/auth/send-verify-code",
            // 其他公开路径
            "/users/login",
            "/users/sms/send",
            "/users/sms/login",
            "/users/admin/login",
            "/actuator/**",
            "/error",
            "/products",
            "/products/*",
            "/banners/active",
            "/tasks",
            "/tasks/*",
            "/settlements",
            "/settlements/*",
            "/database/**"
    );

    /**
     * 从HTTP请求中提取JWT token
     * 支持从Authorization header、自定义header和请求参数中获取token
     *
     * @param request HTTP请求对象
     * @return JWT token字符串，如果不存在则返回null
     */
    private static String extractTokenFromRequest(HttpServletRequest request) {
        if (request == null) {
            return null;
        }

        // 1. 从Authorization header中提取token (标准方式)
        String authHeader = request.getHeader("Authorization");
        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            String token = authHeader.substring(7);
            log.debug("从Authorization header获取到token");
            return token;
        }

        // 2. 从自定义header中提取token
        String tokenHeader = request.getHeader("X-Auth-Token");
        if (tokenHeader != null && !tokenHeader.trim().isEmpty()) {
            log.debug("从X-Auth-Token header获取到token");
            return tokenHeader.trim();
        }

        tokenHeader = request.getHeader("Token");
        if (tokenHeader != null && !tokenHeader.trim().isEmpty()) {
            log.debug("从Token header获取到token");
            return tokenHeader.trim();
        }

        // 3. 从请求参数中提取token (适用于某些特殊场景)
        String tokenParam = request.getParameter("token");
        if (tokenParam != null && !tokenParam.trim().isEmpty()) {
            log.debug("从请求参数token获取到token");
            return tokenParam.trim();
        }

        tokenParam = request.getParameter("auth_token");
        if (tokenParam != null && !tokenParam.trim().isEmpty()) {
            log.debug("从请求参数auth_token获取到token");
            return tokenParam.trim();
        }

        tokenParam = request.getParameter("jwt");
        if (tokenParam != null && !tokenParam.trim().isEmpty()) {
            log.debug("从请求参数jwt获取到token");
            return tokenParam.trim();
        }

        log.debug("未找到有效的JWT token");
        return null;
    }

    /**
     * 获取客户端IP地址
     *
     * @param request HTTP请求对象
     * @return IP地址
     */
    public static String getClientIpAddress(HttpServletRequest request) {
        if (request == null) {
            return "unknown";
        }

        String xForwardedFor = request.getHeader("X-Forwarded-For");
        if (xForwardedFor != null && !xForwardedFor.isEmpty() && !"unknown".equalsIgnoreCase(xForwardedFor)) {
            // 多次反向代理后会有多个IP值，第一个为真实IP
            return xForwardedFor.split(",")[0].trim();
        }

        String xRealIp = request.getHeader("X-Real-IP");
        if (xRealIp != null && !xRealIp.isEmpty() && !"unknown".equalsIgnoreCase(xRealIp)) {
            return xRealIp;
        }

        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }

        return ip;
    }

    /**
     * 获取用户代理信息
     *
     * @param request HTTP请求对象
     * @return User-Agent字符串
     */
    public static String getUserAgent(HttpServletRequest request) {
        if (request == null) {
            return "unknown";
        }
        return request.getHeader("User-Agent");
    }

    /**
     * 从HTTP请求中提取JWT token (公共方法)
     * 支持从Authorization header、自定义header和请求参数中获取token
     *
     * @param request HTTP请求对象
     * @return JWT token字符串，如果不存在则返回null
     */
    public static String extractToken(HttpServletRequest request) {
        return extractTokenFromRequest(request);
    }

    public static boolean isWhiteList(HttpServletRequest request) {
        if (request == null) {
            return false;
        }

        String requestURI = request.getRequestURI();

        // 检查精确匹配
        if (WHITE_LIST.contains(requestURI)) {
            return true;
        }

        // 检查通配符匹配
        for (String pattern : WHITE_LIST) {
            if (pattern.endsWith("/**")) {
                String prefix = pattern.substring(0, pattern.length() - 3);
                if (requestURI.startsWith(prefix)) {
                    return true;
                }
            } else if (pattern.endsWith("/*")) {
                String prefix = pattern.substring(0, pattern.length() - 2);
                if (requestURI.startsWith(prefix) &&
                    requestURI.length() > prefix.length() &&
                    requestURI.charAt(prefix.length()) == '/') {
                    return true;
                }
            }
        }

        return false;
    }
}